SECURITY.md 7c5a9e8652bfefe3d9e95d1fa98b03a39e2e482b (7c5a9e86) Text, 8.36 KB
Tc9d1d9# Security Policy
Tc9d1d9## Contact Information
If you discover a security vulnerability or have concerns about the security of Reticulum MeshChatX, please contact the lead developer using the following methods in order of preference:
Tff7b721. **LXMF**: Ta5d6ff`7cc8d66b4f6a0e0e49d34af7f6077b5a`
For legal inquiries (non-security), contact Ta5d6ff`legal@quad4.io` or see [Ta5d6ff`LEGAL.md`](LEGAL.md).
Tc9d1d9## Security Overview
Reticulum MeshChatX is designed with a high degree of security and privacy in mind, leveraging multiple layers of protection and modern security practices.
We follow the [Tff7b72Electron Best Security Practices](Te6edf3https://www.electronjs.org/docs/latest/tutorial/security).
Tc9d1d9### Exposing to the public internet (with authentication)
MeshChatX is primarily intended for **local or trusted networks** (for example behind a home router or VPN). Putting the HTTP(S) UI on the **public internet** is **not recommended**: you enlarge the attack surface (credential stuffing, TLS and certificate management, reverse-proxy misconfiguration, automated scanning, and denial-of-service against the single-node service).
If you still choose to expose it, **enable authentication**, use **HTTPS** (valid certificates on the public name), restrict **who can reach the port** where possible (firewall allowlists, VPN, or a reverse proxy with additional controls), and keep the app **updated**. The application serves **`/robots.txt`** with **`Disallow: /`** (a hint to crawlers; it is not access control). The application includes **defence-in-depth** for the login and initial-setup endpoints: **per-IP rate limiting**, **lockout** after repeated failed passwords from an address (with **trusted client** recognition after a successful login so your own browsers are less likely to be blocked during broad attacks), **logging** of access attempts (IP, User-Agent, path, time) inspectable under **Debug Logs → Access attempts**, and session cookies configured as **HttpOnly** with **SameSite=Lax**. None of this removes the inherent risks of a public-facing service; it only reduces some abuse and accident scenarios.
Tc9d1d9### Core Security Features
Tff7b72- **ASAR Integrity Validation**: Utilizes Electron 39 features to protect the application against tampering.
Tff7b72- **Backend Binary Verification**: Generates a SHA-256 manifest of the unpacked Python backend during build and verifies it on every startup.
Tff7b72- **Data-at-Rest Integrity Monitoring**: Snapshots the state of identities and database files on clean shutdown and warns if they were modified while the app was closed.
Tff7b72- **CSP Hardening**: Multi-layered Content Security Policy protection across the entire application stack.
Tff7b72- **Hardened Electron Environment**: Hardened security by disabling Ta5d6ff`runAsNode` and Ta5d6ff`nodeOptions` environment variables via Electron Fuses.
Tff7b72- **Rootless Docker Images**: Support for running in restricted environments with rootless container images.
Tc9d1d9### Automated Security Measures
The project employs continuous security monitoring and testing:
Tff7b72- **Security Scanning**: Ta5d6ff`.gitea/workflows/scan.yml` runs on a weekly schedule and on pushes to Ta5d6ff`master` and Ta5d6ff`dev`. It installs frontend dependencies and runs **Trivy filesystem** vulnerabilities on the repo (Ta5d6ff`scripts/ci/trivy-fs-scan.sh`: high and critical severities, exit non-zero on findings), and **Trivy Dockerfile** misconfiguration (Ta5d6ff`trivy config --exit-code 1 Dockerfile`). The **Docker** workflow runs **Trivy** on the built image (Ta5d6ff`trivy image`) separately from that job.
Tff7b72- **Auth and path-safety tests**: Pytest covers HTTP **401** on protected Ta5d6ff`/api/*` when Ta5d6ff`auth_enabled` is on and no session (Ta5d6ff`tests/backend/test_notifications.py`), **ValueError** on backup/snapshot delete paths that escape storage (Ta5d6ff`tests/backend/test_security_path_and_backup.py`), and **schema upgrade** from version **N-1** (Ta5d6ff`tests/backend/test_schema_migration_upgrade.py`). Database **backup/restore** round-trips are covered in Ta5d6ff`tests/backend/test_database_snapshots.py`. Login and setup **rate limiting**, **lockout**, and **access attempt** logging are covered in Ta5d6ff`tests/backend/test_access_attempts_dao.py` and Ta5d6ff`tests/backend/test_access_attempts_enforcement.py` (including Hypothesis and HTTP smoke tests).
Tff7b72- **CI**: On pushes and pull requests, **`pip-audit`** (Python) and **Trivy** (Ta5d6ff`trivy fs` via Ta5d6ff`scripts/ci/trivy-fs-scan.sh`) run against the repository tree (including Node lockfiles and manifests after install where applicable).
Tff7b72- **Pinned Actions**: CI/CD workflows use pinned actions with full URLs to forked, vetted actions hosted on our Gitea instance (Ta5d6ff`git.quad4.io`) where an action is used at all.
Tff7b72- **Extensive Testing & Fuzzing**: Backend benchmarking and stress coverage to reduce instability and resource-exhaustion risks.
Tff7b72- **Linting & Code Quality**: Linting and static analysis run on CI paths.
Tc9d1d9## Release provenance
Tagged releases are built from Ta5d6ff`.gitea/workflows/build.yml`. Release assets include a CycloneDX SBOM (Ta5d6ff`sbom.cyclonedx.json`). When the repository secret **`COSIGN_PRIVATE_KEY`** is set (PEM from Ta5d6ff`cosign generate-key-pair`, with **`COSIGN_PASSWORD`** if the key is encrypted), the workflow also produces **SLSA v1**-style cosign bundle files (Ta5d6ff`*.cosign.bundle`) next to each attested artifact.
Attestations are uploaded to the **Sigstore public transparency log (Rekor)** by default. The build runner must be able to reach the Rekor endpoint (default Ta5d6ff`https://rekor.sigstore.dev`; override with **`COSIGN_REKOR_URL`** if you use another instance).
Commit the cosign **public** key at the **repository root** as **`cosign.pub`** so others can verify without hunting for the key out of band.
Tc9d1d9### Signing key rotation
Rotate the signing key when it may be compromised or on an internal schedule (for example annually). Generate a new key pair, replace the **`COSIGN_PRIVATE_KEY`** (and password) secret in Gitea, and replace **`cosign.pub`** in the repository with the new public key. Releases built **before** rotation remain verifiable using the **old** public key kept alongside the download or in git history; document which key applies to which release tag if you maintain multiple keys.
Tc9d1d9## Verifying releases
Install **[cosign](https://docs.sigstore.dev/cosign/installation/)**. Download the release artifact and its matching **`artifact.cosign.bundle`** from the same release page.
Use a **permalink** to the public key that matches the signing key for that release (same tag or commit as the release, or a known-good commit that still documents the key you trust). Example (replace with your tag or commit as needed):
Tff7b72- **Immutable commit (raw key):**
Ta5d6ff`https://git.quad4.io/RNS-Things/MeshChatX/raw/commit/a3ce41148e6b044d9dc78f2a024fec91d343edb9/cosign.pub`
**Bash or zsh** (no separate key file; process substitution feeds the key to cosign):
Ta5d6ff```Ta5d6ffbash
cosign verify-blob-attestation Tffea00\
--key <Tff7b72(curl -fsSL Ta5d6ff'https://git.quad4.io/RNS-Things/MeshChatX/raw/commit/a3ce41148e6b044d9dc78f2a024fec91d343edb9/cosign.pub'Tff7b72) Tffea00\
--bundle ./MeshChatX-Example.AppImage.cosign.bundle Tffea00\
--type slsaprovenance1 Tffea00\
./MeshChatX-Example.AppImage
Ta5d6ff```
If your shell does not support Ta5d6ff`<(...)`, download the key once and pass a path:
Ta5d6ff```Ta5d6ffbash
curl -fsSL -o cosign.pub Ta5d6ff'https://git.quad4.io/RNS-Things/MeshChatX/raw/commit/a3ce41148e6b044d9dc78f2a024fec91d343edb9/cosign.pub'
cosign verify-blob-attestation Tffea00\
--key cosign.pub Tffea00\
--bundle ./MeshChatX-Example.AppImage.cosign.bundle Tffea00\
--type slsaprovenance1 Tffea00\
./MeshChatX-Example.AppImage
Ta5d6ff```
If you intentionally use a private Sigstore deployment, set the same **`COSIGN_REKOR_URL`** (and any other Sigstore env vars) your builder used.
When CI signing is disabled (no **`COSIGN_PRIVATE_KEY`**), there will be no **`.cosign.bundle`** files for that release.
Tc9d1d9### Container images
Published images are built in Ta5d6ff`.gitea/workflows/docker.yml`. **OCI image cosign signing is not wired in that workflow yet.** Until it is, treat digest pinning as the main integrity check: pull or reference the image by **`@sha256:<digest>`** from a trusted manifest or registry UI, and optionally run **`trivy image`** against that digest. When cosign image signing is added, verification will look like:
Ta5d6ff```Ta5d6ffbash
cosign verify --key cosign.pub <registry>/<image>@sha256:<digest>
Ta5d6ff```
(Exact flags may depend on keyless versus key-based signing; follow the release notes when signing lands.)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────